package com.tomvian.game
{
	import flash.display.DisplayObject;
	import flash.geom.Point;
	import flash.geom.Rectangle;
	
	/**
	 * GameCamera
	 * @author Thomas Vian
	 */
	public class GameCamera
	{
		//--------------------------------------------------------------------------
		//
		//  Properties
		//
		//--------------------------------------------------------------------------
		
		public static var activeCamera:GameCamera;
		
		public var target:DisplayObject;
		public var container:DisplayObject;
		
		public var springConst:Number;
		public var damping:Number;
		
		public var boundBox:Rectangle;
		
		public var x:Number;
		public var y:Number;
		
		private var _speedX:Number;
		private var _speedY:Number;
		
		private var _moving:Boolean;
		
		private var _minX:Number = Number.NEGATIVE_INFINITY;
		private var _minY:Number = Number.NEGATIVE_INFINITY;
		private var _maxX:Number = Number.POSITIVE_INFINITY;
		private var _maxY:Number = Number.POSITIVE_INFINITY;
		
		private var _minSpeedX:Number = 0;
		private var _minSpeedY:Number = 0;
		
		private var _maxSpeedX:Number = Number.POSITIVE_INFINITY;
		private var _maxSpeedY:Number = Number.POSITIVE_INFINITY;
		
		private var _followPoint:Point = new Point();
		
		private var _tickID:uint;
		
		//--------------------------------------------------------------------------
		//
		//  Getters / Setters
		//
		//--------------------------------------------------------------------------
		
		public function get moving():Boolean { return _moving; }
		
		//--------------------------------------------------------------------------
		//
		//  Constructor
		//
		//--------------------------------------------------------------------------
		
		public function GameCamera(target:DisplayObject, container:DisplayObject, boundBox:Rectangle = null, springConst:Number = 0.5, damping:Number = 0.6)
		{
			this.target = target;
			this.container = container;
			
			this.boundBox = boundBox || new Rectangle(275, 200, 1, 1);
			this.springConst = springConst;
			this.damping = damping;
		}
		
		//--------------------------------------------------------------------------
		//
		//  Methods
		//
		//--------------------------------------------------------------------------
		
		public function startFollowing():void
		{
			stopFollowing();
			
			x = container.x;
			y = container.y;
			_speedX = 0;
			_speedY = 0;
			
			activeCamera = this;
			_tickID = TickManager.instance.addTickCall(follow, 1);
		}
		
		public function stopFollowing():void
		{
			activeCamera = null;
			TickManager.instance.removeTickCall(_tickID);
		}
		
		public function follow():void
		{
			if (target.stage)
			{
				_followPoint.x = target.x;
				_followPoint.y = target.y;
				
				_followPoint = target.parent.localToGlobal(_followPoint);
				_followPoint = container.parent.globalToLocal(_followPoint);
				
				var followX:Number = _followPoint.x;
				var followY:Number = _followPoint.y;
				
				if (!boundBox.contains(followX, followY))
				{
					if (followX > boundBox.right)
					{
						// Out to right
						_speedX += (followX - boundBox.right) * springConst
					}
					else if (followX < boundBox.left)
					{
						// Out to left
						_speedX += (followX - boundBox.left)  * springConst;
					}
					
					if (followY > boundBox.bottom)
					{
						// Out to bottom
						_speedY += (followY - boundBox.bottom) * springConst;
					}
					else if (followY < boundBox.top)
					{
						// Out to top
						_speedY += (followY - boundBox.top)  * springConst;
					}
				}
				
				_speedX *= damping;
				_speedY *= damping;
				
				if (_speedX > 0 && _speedX > _maxSpeedX) _speedX = _maxSpeedX;
				if (_speedX < 0 && _speedX < -_maxSpeedX) _speedX = -_maxSpeedX;
				
				if (_speedX > 0 && _speedX < _minSpeedX) _speedX = _minSpeedX;
				if (_speedX < 0 && _speedX > -_minSpeedX) _speedX = -_minSpeedX;
				
				if (_speedY > 0 && _speedY > _maxSpeedY) _speedY = _maxSpeedY;
				if (_speedY < 0 && _speedY < -_maxSpeedY) _speedY = -_maxSpeedY;
				
				if (_speedY > 0 && _speedY < _minSpeedY) _speedY = _minSpeedY;
				if (_speedY < 0 && _speedY > -_minSpeedY) _speedY = -_minSpeedY;
				
				if (_speedX * _speedX + _speedY * _speedY < 0.1) 
				{
					_speedX = 0;
					_speedY = 0;
				}
				
				x -= _speedX;
				y -= _speedY;
				
				if (x > _maxX) x = _maxX;
				if (x < _minX) x = _minX;
				if (y > _maxY) y = _maxY;
				if (y < _minY) y = _minY;
				
				container.x = x;
				container.y = y;
				
				_moving = _speedX != 0 || _speedY != 0;
			}
		}
		
		public function snapToTarget():void
		{
			container.x = x = boundBox.left + boundBox.width * 0.5 - target.x;
			container.y = y = boundBox.top + boundBox.height * 0.5 - target.y;
			
			_speedX = 0;
			_speedY = 0;
		}
		
		public function cleanup():void
		{
			target = null;
			container = null;
		}
	}
}